﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using Twitterizer;
using DownDLL;

namespace melodyMe
{
    public partial class melodyMe : Form
    {
        /// <summary>
        ///TODO: Remove these global variables. BAD BAD BAD! >:|
        /// </summary>
        string searchString;                                                            //The search term being used.
        bool isShown = false;                                                           //Is the Playlist sidebar being shown to the user?
        List<string[]> playlistTracksArray = new List<string[]>();                      //The List<> that stores the info for the Playlist.

        string currentTrackTitle = null;
        string currentTrackArtist = null;

        bool playingFromPlaylist = true;
        WebClient client = new WebClient();                                             //Download Link client.

        //Set as defaultPlaylist to save a headache.
        string saveFileName = "defaultPlaylist";

        public melodyMe()
        {
            InitializeComponent();

            pbLoading.Hide();
            //If the user has okay'd the Disclaimer, enable the button.
            if (Properties.Settings.Default.DL_Disclaimer)
            { btnDownload.Enabled = true; }

            //Get all the playlists before we load one. Show the first playlist.
            Get_Playlists(0);

            if (cboPlaylistDropDown.Items.Count > 0)
            { cboPlaylistDropDown.SelectedItem = cboPlaylistDropDown.Items[0]; }

            LoadSelectedPlaylist();

            myWMPCtrl.PlayStateChange += new AxWMPLib._WMPOCXEvents_PlayStateChangeEventHandler(myWMPCtrl_PlayStateChange);
        }

        void myWMPCtrl_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
        {
            if (playingFromPlaylist)
            {
                switch (e.newState)
                {
                    case 8:
                        {
                            try
                            {
                                if (myPlayList.SelectedIndex >= 0 || myPlayList.SelectedIndex <= myPlayList.Items.Count)
                                {
                                    myPlayList.SelectedIndex++;
                                    playFromPlaylist();
                                }
                                break;
                            }
                            catch (System.Exception) { break; }
                        }

                    case 10:
                        {
                            try
                            {
                                myWMPCtrl.Ctlcontrols.play();
                                break;
                            }
                            catch (System.Exception)
                            { /*myWMPCtrl.Ctlcontrols.play();*/ break; }


                        }
                }
            }
        }

        #region Custom-Playlist Code - Changing Playlists.

        /// <summary>
        /// Gets an array of every playlist from the Playlist folder and stores them in the combobox.
        /// </summary>
        private void Get_Playlists(int thisIndex)
        {
            string playlistDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\melodyMe\\Playlists\\");
            string[] playlists;

            //Clear the list of old data.
            cboPlaylistDropDown.Items.Clear();

            if (!Directory.Exists(playlistDirectory))
            { Directory.CreateDirectory(playlistDirectory); }

            playlists = Directory.GetFiles(playlistDirectory);

            foreach (string file in playlists)
            {
                FileInfo fi = new FileInfo(file);
                cboPlaylistDropDown.Items.Add(fi.Name);
            }

            //Set the shown item as the the first item in te dropdown.
            cboPlaylistDropDown.SelectedItem = thisIndex;


        }

        private void cboPlaylistDropDown_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadSelectedPlaylist();
        }

        private void LoadSelectedPlaylist()
        {
            string mmPL = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\melodyMe\\Playlists\\"+cboPlaylistDropDown.SelectedItem);
            bool PListExists = File.Exists(mmPL);

            if (PListExists)
            {
                //Remove old songs from the arrays/lists.
                myPlayList.Items.Clear();
                playlistTracksArray.Clear();

                try
                {
                    StreamReader streamR = new StreamReader(mmPL);

                    string tempString = streamR.ReadLine();
                    while (tempString != null)
                    {
                        string[] readTrack = tempString.Split('|');

                        myPlayList.Items.Add(readTrack[0]);
                        playlistTracksArray.Add(readTrack);
                        tempString = streamR.ReadLine();
                    }
                    streamR.Close();
                    //Set the filename as this file for saving it.
                    saveFileName = cboPlaylistDropDown.SelectedItem.ToString();
                }
                catch (System.Exception ex) { MessageBox.Show(ex.Message, "melodyMe"); }
            }
        }

        #endregion

        #region Searchbox Code
        /// <summary>
        /// Event occurs when the user presses 'Enter' Key when in focus of the Searchbar.
        /// Initiates a music search.
        /// </summary>
        private void txtSearch_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                searchString = txtSearch.Text;
                GetMusic(searchString);
            }
        }

        /// <summary>
        /// Resets the form back to original pageNumber.
        /// Changes the font colour to black, increased contrast on input readability.
        /// Occurs when the Enter Key is pressed when Searchbox is in focus.
        /// </summary>
        private void txtSearch_Enter(object sender, EventArgs e)
        {
            txtSearch.Clear();
            txtSearch.ForeColor = Color.Black;
        }


        /// <summary>
        /// Resets the Search box if loses focus.
        /// </summary>
        private void txtSearch_Leave(object sender, EventArgs e)
        {
            if (txtSearch.Text == String.Empty)
            {
                txtSearch.Text = "Search";
                txtSearch.ForeColor = Color.LightGray;
            }
        }
        #endregion

        #region Playlist Code - Show/Hide, Adding/Removing Tracks, Save/Load Playlist.
        /// <summary>
        /// Resizes the form to show or hide the Playlist.
        /// Some people just want minimal music-player, keep this in mind.
        /// </summary>
        private void btnShowPList_Click(object sender, EventArgs e)
        {
            try
            {
                if (isShown == false)
                {
                    //Pop the window wider, show the Playlist.
                    this.Size = new System.Drawing.Size(this.Size.Width + 250, this.Size.Height);
                    this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
                    btnShowPList.Text = "Hide Playlist";
                    isShown = true;
                }

                else
                {
                    //Shrink the window, hide the Playlist.
                    this.Size = new System.Drawing.Size(this.Size.Width - 250, this.Size.Height);
                    btnShowPList.Text = "Show Playlist";
                    isShown = false;
                }
            }
            catch (System.Exception) { MessageBox.Show("Oops! An error occurred. Please try again."); }
        }

        /// <summary>
        /// Adds the selected row to the Playlist.
        /// Keeps track of the Title and MP3 Link only.
        /// </summary>
        private void btnAddToPlaylist_Click(object sender, EventArgs e)
        {
            try
            {
                if (listTracks.SelectedItems != null)
                {
                    foreach (ListViewItem lvi in listTracks.SelectedItems)
                    {
                        string[] thisPLTrack = new string[3];
                        thisPLTrack[0] = lvi.SubItems[0].Text;
                        thisPLTrack[1] = lvi.SubItems[3].Text;

                        //Add the Artist, for the Tweet function.
                        thisPLTrack[2] = lvi.SubItems[1].Text;

                        //Add data to listbox and List Array!
                        playlistTracksArray.Add(thisPLTrack);
                        myPlayList.Items.Add(thisPLTrack[0]);
                    }
                }
            }
            catch (System.Exception) { MessageBox.Show("Oops! An error occurred. Please try again. (ERROR: AddToPlaylist)"); }
        }

        /// <summary>
        /// Removes the selected item in the Playlist.
        /// </summary>
        private void btnRmFromPlaylist_Click(object sender, EventArgs e)
        {
            int currentIndex = myPlayList.SelectedIndex;
            if (currentIndex >= 0)
            {
                try
                {
                    //Remove from the Listbox on the form.
                    myPlayList.Items.RemoveAt(currentIndex);

                    //Remove from the List Array we keep the tracks in.
                    playlistTracksArray.RemoveAt(currentIndex);

                    //Make a call to save updated playlist to file.
                    UpdatePlaylist(saveFileName);
                }
                catch (System.Exception) { MessageBox.Show("Oops! An error occurred. Please try again. (ERROR: RmFromPlaylist)"); }
            }

        }

        /// <summary>
        /// Plays the track from the Playlist, as an alternative of the main music-player.
        /// </summary>
        private void myPlayList_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            playingFromPlaylist = true;
            playFromPlaylist();
        }

        /// <summary>
        /// Saves the current playlist over the old playlist on the disk.
        /// Playlists located at: %APPDATA%/musicMe/Playlists/
        /// </summary>
        private void btnSaveToFile_Click(object sender, EventArgs e)
        {
            try
            {
                DialogResult dlg = MessageBox.Show("Save current playlist as: " + saveFileName + "? \nSelect 'No' to change filename.", "melodyMe", MessageBoxButtons.YesNo);

                if (dlg == System.Windows.Forms.DialogResult.No)
                {
                    SaveAsForm newFilename = new SaveAsForm("Save Playlist As...");
                    newFilename.ShowDialog();
                    newFilename.ShowInTaskbar = false;
                    saveFileName = newFilename.FileName;
                }

                UpdatePlaylist(saveFileName);

                //Show messagebox and play sound for confirmation of save.
                System.Media.SystemSounds.Asterisk.Play();
                MessageBox.Show("Current Playlist Saved Successfully.", "melodyMe");
            }
            catch (System.Exception) { MessageBox.Show("Oops! An error occurred. Please try again."); }
        }

        /// <summary>
        /// Saves the current playlist, called whenever an item is added or removed.
        /// Stops the user closing the program and losing a playlist of 20+ songs. 
        /// </summary>
        private void UpdatePlaylist(string updateThisFile)
        {
            try
            {
                //Get the index to come back to for this playlist.
                int currentIndex = cboPlaylistDropDown.SelectedIndex;

                string mmDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\melodyMe\\Playlists\\");
                bool mmDirExists = Directory.Exists(mmDir);

                if (!mmDirExists)
                { Directory.CreateDirectory(mmDir); }

                //Remove the current file to stop non-overwriting. Erm... It makes sense in my head...
                if (File.Exists(mmDir + updateThisFile))
                { File.Delete(mmDir + updateThisFile); }

                StreamWriter streamW = new StreamWriter(mmDir + updateThisFile);
                try
                {
                    foreach (string[] sa in playlistTracksArray)
                    {
                        //Write both parts to a line with the delimiter char.
                        streamW.WriteLine(sa[0] + " | " + sa[1] + " | " + sa[2]);
                    }
                }
                catch { MessageBox.Show("Could not save playlist."); }
                streamW.Close();

                //And update the list of playlists, then show the current playlist!
                Get_Playlists(currentIndex);
                cboPlaylistDropDown.Text = cboPlaylistDropDown.Items[currentIndex].ToString();
            }
            catch (System.Exception) { MessageBox.Show("Oops! An error occurred. Please try again."); }
        }

        /// <summary>
        /// Plays a selected track from the playlist.
        /// Active on: Dub-Click on Playlist Item, or from MediaEnded State 8 of WMPLib.PlayStateChange Event.
        /// </summary>
        private void playFromPlaylist()
        {
            try
            {
                int playlistIndex = myPlayList.SelectedIndex;

                    if (playlistIndex >= 0 && playlistIndex <= myPlayList.Items.Count)
                    {
                        string[] playPLTrack = playlistTracksArray[playlistIndex].ToArray();

                        //Next Two required for Twitter Tweet function.
                        currentTrackTitle = playPLTrack[0];
                        currentTrackArtist = playPLTrack[2];

                        playTrack(playPLTrack[1]);
                    }
            }
            catch (System.Exception ex) { MessageBox.Show(ex.Message, "melodyMe"); }
        }

        #endregion

        #region Track Playing Code
        /// <summary>
        /// Gets the selected row's MP3 Link and uses the WMPControl to play it.
        /// </summary>
        private void listTracks_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            string myLink = null;
            if (listTracks.FocusedItem.Text != null)
            {
                currentTrackTitle = listTracks.FocusedItem.SubItems[0].Text;
                currentTrackArtist = listTracks.FocusedItem.SubItems[1].Text;

                //Get the 'MP3 Link' Column's Text, of the selected row.
                myLink = listTracks.FocusedItem.SubItems[3].Text;
  
            }

            //Play Selected Track 
            myWMPCtrl.URL = myLink;
            myWMPCtrl.Ctlcontrols.play();
        }


        /// <summary>
        /// Method that plays a track.
        /// </summary>
        /// <param name="trackURL">The URL of the MP3 Link.</param>
        private void playTrack(string trackURL)
        {
            try
            {
                myWMPCtrl.URL = trackURL;
                myWMPCtrl.Ctlcontrols.play();
            }
            catch (System.Exception) { }
        }

        #endregion

        #region GetMusic() Method + Other Misc Code
        /// <summary>
        /// Gets the tracks from the HTTP request and shows the data in the ListView control.
        /// </summary>
        /// <param name="pageNum">The Pagenumber passed to the dataManager Class.</param>
        /// <param name="searchString">The string to pass to the server with respect of tracks returned.</param>
        public void GetMusic(string searchString)
        {
            try
            {
                string strSearchString = searchString;
                pbLoading.Show();
                bgWorker.RunWorkerAsync(strSearchString);
            }
            catch(Exception) { }

        }

        /// <summary>
        /// Background Worker Event for performing Async connection/downloading
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            //Ripped from Downstream. Consider it a parting gift, folks. ;)
            string strSearchString = (string)e.Argument;
            List<Track> trackData = ID3Class.GenerateTrackList(strSearchString, 10);
            e.Result = trackData;
        }

        /// <summary>
        /// Called as the BG Worker completes to populate the ListView for Track data.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void bgWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            pbLoading.Hide();
            List<Track> trackListing = e.Result as List<Track>;
            listTracks.Items.Clear();

            //Fill in the ListView with the data.

            if (e.Result != null)
            {
                foreach (Track trk in trackListing)
                {
                    string[] lvi_TrackStrings = { trk.Title, trk.Artist, trk.Album, trk.Link };
                    ListViewItem lvi_TrackItem = new ListViewItem(lvi_TrackStrings);
                    listTracks.Items.Add(lvi_TrackItem);
                }
            }
        }

        /// <summary>
        /// Disables resizing of the ListView that holds the track data.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listTracks_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
        {
            if (e.ColumnIndex == 0)
            { e.Cancel = true; e.NewWidth = 307; }

            if (e.ColumnIndex == 1)
            { e.Cancel = true; e.NewWidth = 187; }

            if (e.ColumnIndex == 2)
            { e.Cancel = true; e.NewWidth = 196; }
        }
        #endregion

        #region MenuStrip Code (Preferences, About, Online Guides Etc)
        private void preferencesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PreferencesForm prefForm = new PreferencesForm();
            prefForm.ShowIcon = true;
            prefForm.ShowInTaskbar = false;

            prefForm.Owner = this;
            prefForm.ShowDialog();
        }
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox abBox = new AboutBox();
            abBox.ShowInTaskbar = false;
            abBox.ShowDialog();
        }
        private void onlineHelpGuidesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start("http://melodyme.codeplex.com/documentation");
        }
        private void tweetTrackToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Make new OAuthToken from authorized data.
            OAuthTokens oAuthKeychain = new OAuthTokens()
            {
                AccessToken = Properties.Settings.Default.access_token,
                AccessTokenSecret = Properties.Settings.Default.access_secret,
                ConsumerKey = Properties.Settings.Default.consumer_key,
                ConsumerSecret = Properties.Settings.Default.consumer_secret
            };

            //Check there's a token stored for the user before we continue.
            if (!String.IsNullOrEmpty(Properties.Settings.Default.access_token))
            {
                //Try using a string with Track Title and Artist in it.
                string TArtAndTitle = "I'm listening to \"" + currentTrackTitle + " by" + currentTrackArtist + "\" on #melodyMe!";
                if (currentTrackTitle != null)
                {
                    if (TArtAndTitle.Length > 140)
                    {
                        //It's more than 140, so trim it down and drop the Artist...
                        TArtAndTitle = "I'm listening to \"" + currentTrackTitle + "\" on #melodyMe!";

                        if (currentTrackTitle.Length > 107)
                        {
                            //If it's longer than 107, trim it.
                            currentTrackTitle = TArtAndTitle.Substring(0, 107);
                            currentTrackTitle = currentTrackTitle.Trim();
                            TwitterStatus.Update(oAuthKeychain, "I'm listening to \"" + currentTrackTitle + "\" on #melodyMe!");
                            MessageBox.Show("New Tweet Added:\n" + TArtAndTitle, "melodyMe");
                        }
                    }
                    else
                    {
                        currentTrackTitle = currentTrackTitle.Trim();
                        currentTrackArtist = currentTrackArtist.Trim();
                        TwitterStatus.Update(oAuthKeychain, TArtAndTitle);
                        MessageBox.Show("New Tweet Added:\n" + TArtAndTitle, "melodyMe");
                    }
                }
            }

            else
            {
                MessageBox.Show("You are not yet authenticated for Twitter! \nUse the Preferences Window (File --> Preferences --> Twitter) to log in!", "melodyMe");
            }
        }
        private void playlistEditorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PlaylistDJ DJForm = new PlaylistDJ();
            DJForm.ShowDialog();
            Get_Playlists(0);

            if (Properties.Settings.Default.DL_Disclaimer == true)
            { btnDownload.Enabled = true; }
        }
        private void onlineHelpGuidesToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            Process.Start("http://melodyme.codeplex.com/documentation");
        }
        private void whatsNewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            whatsNewBox changelogForm = new whatsNewBox();
            changelogForm.ShowDialog();
        }
        #endregion

        #region Download Code
        private void btnDownload_Click(object sender, EventArgs e)
        {
            try
            {
                if (btnDownload.Text == "Download Track")
                {
                    string musicDL_Folder = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic) + "\\melodyMeDownloads";

                    if (!Directory.Exists(musicDL_Folder))
                        Directory.CreateDirectory(musicDL_Folder);


                    if (listTracks.FocusedItem != null)
                    {
                        btnDownload.Text = "Cancel Download";
                        string title = listTracks.FocusedItem.SubItems[0].Text;
                        string mp3Link = listTracks.FocusedItem.SubItems[3].Text;
                        string mp3Location = musicDL_Folder + "\\" + title + ".mp3";

                        Uri uri = new Uri(mp3Link);

                        client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
                        client.DownloadFileAsync(uri, mp3Location);

                        return;
                    }
                }
                else
                {
                    client.CancelAsync();
                    tsProgressBar.Value = 0;
                    tsProgressText.Text = "";
                    btnDownload.Enabled = true;
                    btnDownload.Text = "Download Track";
                    return;
                }
            }

            catch (System.Exception ex) { MessageBox.Show("Error:\n" + ex.Message, "melodyMe"); }
        }

        private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            tsProgressBar.Value = e.ProgressPercentage;
            tsProgressText.Text = "Progress: " + tsProgressBar.Value + "%";

            //It's been a year or so, and I still can't get to the root of the dupe MessageBox objects.
            //Incredibly minor for Issue Tracker, so I shall leave it up for Misc. Fixes - Matt (Insomnica)
            if (e.ProgressPercentage == 100)
            {
                tsProgressText.Text = "";
                tsProgressBar.Value = 0;
                btnDownload.Text = "Download Track";
                btnDownload.Enabled = true;
                MessageBox.Show("Track Downloaded!\n Saved to \"My Music\" > \"melodyMeDownloads\"", "melodyMe",
                                                              MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

        }
        #endregion

        #region Lyrics Code
        /// <summary>
        /// Finds lyrics from a website, and presents them.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLyrics_Click(object sender, EventArgs e)
        {
            LyricsForm lyricsForm = new LyricsForm(currentTrackArtist, currentTrackTitle);
            lyricsForm.ShowDialog();
        }
        #endregion
    }
}

